package org.example.MedicalCrowdsourcing.service;

import org.example.MedicalCrowdsourcing.mapper.ProjectMapper;
import org.example.MedicalCrowdsourcing.model.dto.ProjectCreateDTO;
import org.example.MedicalCrowdsourcing.model.dto.ProjectDTO;
import org.example.MedicalCrowdsourcing.model.dto.ProjectDataDTO;
import org.example.MedicalCrowdsourcing.model.entity.Project;
import org.example.MedicalCrowdsourcing.model.entity.ProjectData;
import org.example.MedicalCrowdsourcing.model.entity.Role;
import org.example.MedicalCrowdsourcing.model.entity.User;
import org.example.MedicalCrowdsourcing.repository.ProjectDataRepository;
import org.example.MedicalCrowdsourcing.repository.ProjectRepository;
import org.example.MedicalCrowdsourcing.repository.UserRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.security.access.AccessDeniedException;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class ProjectService {
    private static final Logger logger = LoggerFactory.getLogger(ProjectService.class);

    private final ProjectRepository projectRepository;
    private final ProjectDataRepository projectDataRepository;
    private final UserRepository userRepository;
    private final ProjectMapper projectMapper;

    @Autowired
    public ProjectService(ProjectRepository projectRepository, 
                          ProjectDataRepository projectDataRepository,
                          UserRepository userRepository,
                          ProjectMapper projectMapper) {
        this.projectRepository = projectRepository;
        this.projectDataRepository = projectDataRepository;
        this.userRepository = userRepository;
        this.projectMapper = projectMapper;
    }

    /**
     * 创建新项目
     */
    @Transactional
    public ProjectDTO createProject(ProjectCreateDTO projectCreateDTO, Long researcherId) {
        User researcher = userRepository.findById(researcherId)
                .orElseThrow(() -> new RuntimeException("Researcher not found with id: " + researcherId));
        
        Project project = projectMapper.toEntity(projectCreateDTO);
        project.setResearcher(researcher);
        project.setCreatedAt(LocalDateTime.now());
        project.setStatus("OPEN");
        
        Project savedProject = projectRepository.save(project);
        return projectMapper.toDto(savedProject);
    }

    /**
     * 获取所有项目
     */
    public List<ProjectDTO> getAllProjects() {
        return projectRepository.findAll().stream()
                .map(projectMapper::toDto)
                .collect(Collectors.toList());
    }

    /**
     * 通过ID获取项目
     */
    public ProjectDTO getProjectById(Long id) {
        Project project = projectRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + id));
        return projectMapper.toDto(project);
    }

    /**
     * 获取研究者的所有项目
     */
    public List<ProjectDTO> getProjectsByResearcher(Long researcherId) {
        User researcher = userRepository.findById(researcherId)
                .orElseThrow(() -> new RuntimeException("Researcher not found with id: " + researcherId));
        return projectRepository.findByResearcher(researcher).stream()
                .map(projectMapper::toDto)
                .collect(Collectors.toList());
    }

    /**
     * 获取参与者的所有项目
     */
    public List<ProjectDTO> getProjectsByParticipant(Long participantId) {
        User participant = userRepository.findById(participantId)
                .orElseThrow(() -> new RuntimeException("Participant not found with id: " + participantId));
        return projectRepository.findByParticipantsContaining(participant).stream()
                .map(projectMapper::toDto)
                .collect(Collectors.toList());
    }

    /**
     * 更新项目
     * 添加所有权检查: 只有项目创建者(研究者)或管理员可以修改项目
     */
    @Transactional
    public ProjectDTO updateProject(Long projectId, ProjectCreateDTO projectUpdateDTO, User currentUser) {
        Project existingProject = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        // 检查是否为项目创建者或管理员
        boolean isAdmin = currentUser.getRole().getId().equals(Role.ADMIN);
        boolean isCreator = existingProject.getResearcher().getId().equals(currentUser.getId());
        
        if (!isCreator && !isAdmin) {
            throw new AccessDeniedException("您没有权限修改其他研究者的项目");
        }
        
        // ProjectCreateDTO中没有研究者信息，因此不需要检查是否修改了项目创建者
        // 如果将来需要添加，应在此处添加检查
        
        // 更新项目字段
        existingProject.setTitle(projectUpdateDTO.getTitle());
        existingProject.setDescription(projectUpdateDTO.getDescription());
        existingProject.setStartDate(projectUpdateDTO.getStartDate());
        existingProject.setEndDate(projectUpdateDTO.getEndDate());
        existingProject.setRequiredParticipants(projectUpdateDTO.getRequiredParticipants());
        existingProject.setRequiredDataTypes(projectUpdateDTO.getRequiredDataTypes());
        existingProject.setParticipantCriteria(projectUpdateDTO.getParticipantCriteria());
        existingProject.setCompensationAmount(projectUpdateDTO.getCompensationAmount());
        existingProject.setUpdatedAt(LocalDateTime.now());
        
        Project updatedProject = projectRepository.save(existingProject);
        return projectMapper.toDto(updatedProject);
    }

    /**
     * 删除项目
     * 添加所有权检查: 只有项目创建者(研究者)或管理员可以删除项目
     */
    @Transactional
    public void deleteProject(Long projectId, User currentUser) {
        Project project = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        // 检查是否为项目创建者或管理员
        boolean isAdmin = currentUser.getRole().getId().equals(Role.ADMIN);
        boolean isCreator = project.getResearcher().getId().equals(currentUser.getId());
        
        if (!isCreator && !isAdmin) {
            throw new AccessDeniedException("您没有权限删除其他研究者的项目");
        }
        
        projectRepository.delete(project);
    }

    /**
     * 用户参与项目
     */
    @Transactional
    public ProjectDTO joinProject(Long projectId, Long participantId) {
        Project project = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        User participant = userRepository.findById(participantId)
                .orElseThrow(() -> new RuntimeException("Participant not found with id: " + participantId));
        
        if (project.getParticipants().contains(participant)) {
            throw new RuntimeException("Participant is already enrolled in this project");
        }
        
        if (project.getParticipants().size() >= project.getRequiredParticipants()) {
            throw new RuntimeException("Project has reached the maximum number of participants");
        }
        
        project.getParticipants().add(participant);
        Project updatedProject = projectRepository.save(project);
        return projectMapper.toDto(updatedProject);
    }

    /**
     * 用户退出项目
     */
    @Transactional
    public ProjectDTO withdrawFromProject(Long projectId, Long participantId) {
        Project project = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        User participant = userRepository.findById(participantId)
                .orElseThrow(() -> new RuntimeException("Participant not found with id: " + participantId));
        
        if (!project.getParticipants().contains(participant)) {
            throw new RuntimeException("Participant is not enrolled in this project");
        }
        
        project.getParticipants().remove(participant);
        Project updatedProject = projectRepository.save(project);
        return projectMapper.toDto(updatedProject);
    }

    /**
     * 提交项目数据
     */
    @Transactional
    public ProjectDataDTO submitData(Long projectId, Long participantId, ProjectDataDTO projectDataDTO) {
        Project project = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        User participant = userRepository.findById(participantId)
                .orElseThrow(() -> new RuntimeException("Participant not found with id: " + participantId));
        
        if (!project.getParticipants().contains(participant)) {
            throw new RuntimeException("Participant is not enrolled in this project");
        }
        
        ProjectData projectData = new ProjectData();
        projectData.setProject(project);
        projectData.setParticipant(participant);
        projectData.setDataContent(projectDataDTO.getDataContent());
        projectData.setDataType(projectDataDTO.getDataType());
        projectData.setSubmissionDate(LocalDateTime.now());
        projectData.setStatus("SUBMITTED");
        
        ProjectData savedData = projectDataRepository.save(projectData);
        
        ProjectDataDTO savedDataDTO = new ProjectDataDTO();
        savedDataDTO.setId(savedData.getId());
        savedDataDTO.setProjectId(project.getId());
        savedDataDTO.setParticipantId(participant.getId());
        savedDataDTO.setDataContent(savedData.getDataContent());
        savedDataDTO.setDataType(savedData.getDataType());
        savedDataDTO.setSubmissionDate(savedData.getSubmissionDate());
        savedDataDTO.setStatus(savedData.getStatus());
        
        return savedDataDTO;
    }

    /**
     * 关闭项目
     */
    @Transactional
    public ProjectDTO closeProject(Long projectId) {
        Project project = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        project.setStatus("CLOSED");
        project.setEndDate(LocalDateTime.now());
        project.setUpdatedAt(LocalDateTime.now());
        
        Project updatedProject = projectRepository.save(project);
        return projectMapper.toDto(updatedProject);
    }

    /**
     * 获取项目数据
     */
    public List<ProjectDataDTO> getProjectDataByProject(Long projectId) {
        Project project = projectRepository.findById(projectId)
                .orElseThrow(() -> new RuntimeException("Project not found with id: " + projectId));
        
        return projectDataRepository.findByProject(project).stream()
                .map(this::convertToProjectDataDTO)
                .collect(Collectors.toList());
    }

    /**
     * 获取参与者数据
     */
    public List<ProjectDataDTO> getProjectDataByParticipant(Long participantId) {
        User participant = userRepository.findById(participantId)
                .orElseThrow(() -> new RuntimeException("Participant not found with id: " + participantId));
        
        return projectDataRepository.findByParticipant(participant).stream()
                .map(this::convertToProjectDataDTO)
                .collect(Collectors.toList());
    }

    private ProjectDataDTO convertToProjectDataDTO(ProjectData projectData) {
        ProjectDataDTO dto = new ProjectDataDTO();
        dto.setId(projectData.getId());
        dto.setProjectId(projectData.getProject().getId());
        dto.setParticipantId(projectData.getParticipant().getId());
        dto.setDataContent(projectData.getDataContent());
        dto.setDataType(projectData.getDataType());
        dto.setSubmissionDate(projectData.getSubmissionDate());
        dto.setStatus(projectData.getStatus());
        return dto;
    }
} 